﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Net;
using System.Web;
using System.Windows.Forms;
using Microsoft.SharePoint.Administration;
using Wagner.Utilities;
//using System.GAC;

namespace Wagner.SharePoint.Utilities
{
	internal class GenWS : OperationBase
	{
		internal GenWS()
		{}

		#region Properties

		//private Arguments myArgs;
		//private Arguments Args
		//{
		//   get { return (myArgs == null) ? myArgs = new Arguments(Environment.GetCommandLineArgs()) : myArgs; }
		//}

		private string Url
		{
			get { return Args["url"]; }
		}

		private string WebServiceUrl
		{
			get{ return Url + "/_layouts/temp/" + SourceAsmx.Name; }
		}

		private string WebServiceName
		{
			get{ return Path.GetFileNameWithoutExtension(WebServiceUrl); }
		}

		private string DiscoUrl 
		{
			get{ return WebServiceUrl + "?disco"; }
		}

		private string WsdlUrl 
		{
			get{ return WebServiceUrl + "?wsdl"; }
		}

		private string DiscoFileName 
		{
			get{ return WebServiceName + ".disco"; }
		}

		private string WsdlFileName 
		{
			get{ return WebServiceName + ".wsdl"; }
		}

		private string DiscoAspxFileName 
		{
			get{ return WebServiceName + "disco.aspx"; }
		}

		private string WsdlAspxFileName 
		{
			get{ return WebServiceName + "wsdl.aspx"; }
		}

		private string AspxPageHeading
		{
			get
			{
				return @"<%@ Page Language=""C#"" Inherits=""System.Web.UI.Page"" %> 
<%@ Assembly Name=""Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"" %> 
<%@ Import Namespace=""Microsoft.SharePoint.Utilities"" %> 
<%@ Import Namespace=""Microsoft.SharePoint"" %>
<% Response.ContentType = ""text/xml""; %>";
			}
		}

		private FileInfo mySourceAsmx;
		private FileInfo SourceAsmx
		{
			get 
			{ 
				if( mySourceAsmx == null )
					mySourceAsmx = new FileInfo(Args["asmx"]); 

				return mySourceAsmx;
			}
		}

		private FileInfo myTargetAsmx;
		private FileInfo TargetAsmx
		{
			get 
			{ 
				if( myTargetAsmx == null )
					myTargetAsmx = new FileInfo(LayoutsTemp.FullName + "\\" + SourceAsmx.Name);

				return myTargetAsmx;
			}
		}

		#endregion

		internal override void Run()
		{
			Console.WriteLine(@"SPDev generating SharePoint web service files:");

			// Testing only
			//IISHelper.ListAppPool(Args["server"], "mark", "Wagner#1", "" );
			//IISHelper.GetSiteID(Args["server"], "mark", "Wagner#1", "SharePoint - 80");
			//IISHelper.ListIisApplicationPoolProperties(Args["server"], "mark", "Wagner#1", null);

			string url = ValidateParameter("url", true, null);
			string asmx = ValidateParameter("asmx", true, null);

			// Clean up any pre-existing target .asmx file.
			CleanUpFile(TargetAsmx);
			
			// Copy .asmx file to the 12\TEMPLATE\LAYOUTS\Temp folder.
			Console.Write(@"Copying .asmx file to working folder...");
			SourceAsmx.CopyTo(TargetAsmx.FullName, true);
			Console.WriteLine(" done.");

			// Copy the assembly to the GAC
			//if (Args["gac"] != null)
			//{
			//   string assemblyPath = Args["gac"];
			//   GACUtility.GacAssembly(Args["gac"]);
			//}
			
			// Recycle the application pool for the web application url.
			SPApplicationPool appPool = IISUtilities.GetApplicationPool(url);
			Console.Write(string.Format("Recycling the application pool '{0}'...", appPool.DisplayName));
			IISUtilities.RecycleApplicationPool(appPool.DisplayName);
			Console.WriteLine(" done.");

			// Generate the standard .disco and .wsdl files and save them to the temp folder.
			Console.Write("Generating .disco and .wsdl files...");
			string disco = GetWebPage(DiscoUrl).Trim();
			string wsdl = GetWebPage(WsdlUrl).Trim();
			Console.WriteLine("done.");

			// Perform a rudimentry validation that the .disco and .wsdl files are 
			// valid files and not error files generated by the web server.
			if (!IsDiscoFile(disco))
			{
				SaveFile(disco, TempFilePath(DiscoFileName));
				throw new Exception(string.Format("Web service .disco file is not a valid DISCO file. File {0} saved in the temp folder.", DiscoFileName));
			}

			if (!IsWsdlFile(wsdl))
			{
				SaveFile(wsdl, TempFilePath(WsdlFileName));
				throw new Exception(string.Format("Web service .wsdl file is not a valid WSDL file. File {0} saved in the temp folder.", WsdlFileName));
			}

			// Save temp .disco and .wsdl files?
			if (Args["tempfiles"] == "true")
			{
				SaveFile(disco, TempFilePath(DiscoFileName));
				Console.WriteLine(" " + DiscoFileName + " saved to Temp folder.");
				SaveFile(wsdl, TempFilePath(WsdlFileName));
				Console.WriteLine(" " + WsdlFileName + " saved to Temp folder.");
			}

			// Modify disco and wsdl files for use as a SharePoint web service.
			Console.WriteLine("Generating web service .aspx files...");
			SaveFile(GetDiscoAspx(disco), OutputFilePath(DiscoAspxFileName));
			Console.WriteLine(" " + DiscoAspxFileName + " saved to Temp folder.");
			SaveFile(GetWsdlAsxp(wsdl), OutputFilePath(WsdlAspxFileName));
			Console.WriteLine(" " + WsdlAspxFileName + " saved to Temp folder.");

			// Deploy web service files
			if (Args["deploy"] == "true")
			{
				Console.WriteLine("Deploying web service files to SharePoint...");
				
				FileInfo isapiAsmxFile = new FileInfo(IsapiFilePath(SourceAsmx.Name));
				RemoveReadOnly(isapiAsmxFile);
				SourceAsmx.CopyTo(IsapiFilePath(SourceAsmx.Name), true);
				Console.WriteLine(" " + SourceAsmx.Name + " deployed.");
				RemoveReadOnly(isapiAsmxFile);

				SaveFile(GetDiscoAspx(disco), IsapiFilePath(DiscoAspxFileName));
				Console.WriteLine(" " + DiscoAspxFileName + " deployed.");
				SaveFile(GetWsdlAsxp(wsdl), IsapiFilePath(WsdlAspxFileName));
				Console.WriteLine(" " + WsdlAspxFileName + " deployed.");
			}

			// Cleanup
			Console.Write("Cleaning up working .asmx file...");
			CleanUpFile(TargetAsmx);
			Console.WriteLine(" done.");

			Console.WriteLine("SPDev completed successfully.");
		}
		
		private string GetDiscoAspx(string disco)
		{
			string aspx = disco;

			// Insert aspx page heading references
			aspx = aspx.Insert(0, AspxPageHeading);

			// Replace the ContractRef ref attribute (?wsdl url).
			aspx = aspx.Replace(QuotedString(WsdlUrl), @"<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request) + ""?wsdl""),Response.Output); %>");

			// Replace the ContractRef refdoc attribute.
			aspx = aspx.Replace(QuotedString(WebServiceUrl), @"<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request)),Response.Output); %>");
			
			return aspx;
		}

		private bool IsDiscoFile(string disco)
		{
			string discoVerifyString = @"discovery xmlns";
			return disco.Contains(discoVerifyString);
		}

		private bool IsWsdlFile(string wsdl)
		{
			string wsdlVerifyString = @"wsdl:definitions";
			return wsdl.Contains(wsdlVerifyString);
		}

		private string GetWsdlAsxp(string wsdl)
		{
			string aspx = wsdl;

			// Replace xml heading with asxp page heading references
			aspx = aspx.Replace(@"<?xml version=""1.0"" encoding=""utf-8""?>", AspxPageHeading);

			// Replace the web service soap location attribute
			aspx = aspx.Replace(QuotedString(WebServiceUrl), @"<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request)),Response.Output); %>");
			
			return aspx;
		}
		
		private string GetWebPage(string url)
		{
			// Request web page.
			WebRequest webRequest = WebRequest.Create(url);
			webRequest.UseDefaultCredentials = true;
			WebResponse webResponse = webRequest.GetResponse();
			Stream webStream = webResponse.GetResponseStream();
			
			// Read contents into a working variable.
			StreamReader reader = new StreamReader(webStream, Encoding.UTF8);
			string response = reader.ReadToEnd();
			reader.Close();
			webStream.Close();
			webResponse.Close();

			return response;
		}
		

		private string IsapiFilePath(string filename)
		{
			DirectoryInfo path = new DirectoryInfo(IsapiPath);
			return path.FullName + "\\" + filename;
		}

		internal override string HelpSummary
		{
			get
			{
				return @"
-o GenWS 
     Generates the SharePoint web service disco.aspx and wsdl.aspx files.
     * No need to manually edit your .disco and .wsdl files to work with
     SharePoint. This generates the final disco.aspx and wsdl.aspx files
     automatically.";
			}
		}

		internal override string HelpDetail
		{
			get
			{
				string help = HelpSummary + @"
Usage:
  SPDev.exe -o GenWS -url <url> -asmx <filename>
       
    Parameters: 
     -url <web server url>
       Specifies the url to the SharePoint web application. This only needs
       to be the URL to the root web application site. A url value of 
       http://localhost may be used for easy use by several developers.
    
     -asmx <filename>
       Specifies the web service .asmx file name. This may be an absolute or
       relative path.
    
     [-tempfiles]
       Saves the standard .disco and .wsdl generated files to the Temp folder.
       These are the standard non-SharePoint web service .disco and .wsdl files,
       which are used to create the final SharePoint disco.aspx and wsdl.aspx 
       web service files.  A subfolder named “Temp” is created.
   
     [-temppath] <path>
       Specifies a custom path to use for temporary files.  When omitted, a
       subfolder named “Temp” is created, if the –tempfiles option is specified.
       May be a relative or absolute path.
  
     [-outpath] <path>
       Specifies a custom path to place the generated SharePoint web service 
       .aspx files.  When omitted, the path defaults to the current execution 
       folder.  May be a relative or absolute path.
   
     [-deploy]
       Copies the generated web service disco.aspx and wsdl.aspx files to the
       standard web services SharePoint ISAPI (_vti_bin) folder. 
       IMPORTANT: This is not the recommended deployment method for 
       production environments. 

Additional Arguments (available with any operation):
     [-debug] 
       Displays stack track for any exception message to the console. 

     [-pause]
       Pauses the command on completion. Press any key to continue. 

Examples:
SPDev.exe -o GenWS -url http://localhost -asmx My.asmx
SPDev.exe -o GenWS -url http://localhost -asmx My.asmx –deploy
SPDev.exe -o GenWS -url http://localhost -asmx My.asmx –tempfiles -debug

";

				return help;
			}
		}


	}	

}
